﻿using System;
using System.Collections;
using System.IO;
using System.Reflection;
using System.Text;
using System.Web;
using System.Web.UI;
using NV = System.Collections.Specialized.NameValueCollection;
using UCPostData = System.Collections.Generic.Dictionary<string, object>;
using System.Diagnostics;

namespace UCenterLib {
    public delegate void UCCallBack(object sender, UCEventArgs args);

    public class UCApiHandler : IHttpHandler {
        readonly static string UC_CLIENT_VERSION = "1.5.0";
        readonly static string UC_CLIENT_RELEASE = "20090121";

        protected readonly static int API_RETURN_SUCCEED = 1;
        protected readonly static int API_RETURN_FAILED = -1;
        protected readonly static int API_RETURN_FORBIDDEN = -2;

        // DEFINE ALL EVENTS
        public event UCCallBack Test;
        public event UCCallBack DeleteUser;
        public event UCCallBack RenameUser;
        public event UCCallBack GetTag;
        public event UCCallBack SynLogin;
        public event UCCallBack SynLogout;
        public event UCCallBack UpdatePassword;
        public event UCCallBack UpdateBadWords;
        public event UCCallBack UpdateHosts;
        public event UCCallBack UpdateApps;
        public event UCCallBack UpdateClient;
        public event UCCallBack UpdateCredit;
        public event UCCallBack GetCredit;
        public event UCCallBack GetCreditSettings;
        public event UCCallBack UpdateCreditSettings;

        #region EVENT INVOKERS
        /// <summary>
        /// 此接口供仅测试连接。当 UCenter 发起 test 的接口请求时，如果成功获取到接口返回的 API_RETURN_SUCCEED 值，表示 UCenter 和应用通讯正常。 
        /// </summary>
        protected virtual void OnTest(UCEventArgs e) {
            e.Context.Response.Write(API_RETURN_SUCCEED.ToString());
            e.Context.Response.End();
        }

        /// <summary>
        /// 当 UCenter 删除一个用户时，会发起 deleteuser 的接口请求，通知所有应用程序删除相应的用户。
        /// 输入的参数放在 $get['ids'] 中，值为用逗号分隔的用户 ID。如果删除成功则输出 API_RETURN_SUCCEED。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void OnDeleteUser(UCEventArgs e) {
            UCCallBack handler = ACTION_TRANS_EVENTS["deleteuser"] as UCCallBack;
            if (handler != null) {
                handler(this, e);
            } else {
                e.Context.Response.Write(API_RETURN_FORBIDDEN);
                e.Context.Response.End();
            }
        }

        /// <summary>
        /// 当 UCenter 更改一个用户的用户名时，会发起 renameuser 的接口请求，通知所有应用程序改名。
        /// 输入的参数 $get['uid'] 表示用户 ID，$get['oldusername'] 表示旧用户名，$get['newusername'] 表示新用户名。如果修改成功则输出 API_RETURN_SUCCEED。
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnRenameUser(UCEventArgs e) {
            UCCallBack handler = ACTION_TRANS_EVENTS["renameuser"] as UCCallBack;
            if (handler != null) {
                handler(this, e);
            } else {
                e.Context.Response.Write(API_RETURN_FORBIDDEN);
                e.Context.Response.End();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnGetTag(UCEventArgs e) {
            UCCallBack handler = ACTION_TRANS_EVENTS["gettag"] as UCCallBack;
            if (handler != null) {
                handler(this, e);
            } else {
                e.Context.Response.Write(API_RETURN_FORBIDDEN);
                e.Context.Response.End();
            }
        }

        /// <summary>
        /// 如果应用程序需要和其他应用程序进行同步登录，此部分代码负责标记指定用户的登录状态。
        /// 输入的参数放在 $get['uid'] 中，值为用户 ID。此接口为通知接口，无输出内容。同步登录需使用 P3P 标准。
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnSynLogin(UCEventArgs e) {
            UCCallBack handler = ACTION_TRANS_EVENTS["synlogin"] as UCCallBack;
            if (handler != null) {
                handler(this, e);
            } 
        }

        /// <summary>
        /// 如果应用程序需要和其他应用程序进行同步退出登录，此部分代码负责撤销用户的登录的状态。
        /// 此接口为通知接口，无输入参数和输出内容。同步退出需使用 P3P 标准。
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnSynLogout(UCEventArgs e) {
            UCCallBack handler = ACTION_TRANS_EVENTS["synlogout"] as UCCallBack;
            if (handler != null) {
                handler(this, e);
            } 
        }

        protected virtual void OnUpdatePassword(UCEventArgs e) {
            UCCallBack handler = ACTION_TRANS_EVENTS["updatepw"] as UCCallBack;
            if (handler != null) {
                handler(this, e);
            } else {
                e.Context.Response.Write(API_RETURN_FORBIDDEN);
                e.Context.Response.End();
            }
        }

        protected virtual void OnUpdateBadWords(UCEventArgs e) {
            UCCallBack handler = ACTION_TRANS_EVENTS["updatebadwords"] as UCCallBack;
            if (handler != null) {
                handler(this, e);
            } else {
                e.Context.Response.Write(API_RETURN_FORBIDDEN);
                e.Context.Response.End();
            }
        }

        protected virtual void OnUpdateHosts(UCEventArgs e) {
            UCCallBack handler = ACTION_TRANS_EVENTS["updatehosts"] as UCCallBack;
            if (handler != null) {
                handler(this, e);
            } else {
                e.Context.Response.Write(API_RETURN_FORBIDDEN);
                e.Context.Response.End();
            }
        }

        protected virtual void OnUpdateApps(UCEventArgs e) {
            UCCallBack handler = ACTION_TRANS_EVENTS["updateapps"] as UCCallBack;
            if (handler != null) {
                handler(this, e);
            } else {
                e.Context.Response.Write(API_RETURN_FORBIDDEN);
                e.Context.Response.End();
            }
        }

        protected virtual void OnUpdateClient(UCEventArgs e) {
            UCCallBack handler = ACTION_TRANS_EVENTS["updateclient"] as UCCallBack;
            if (handler != null) {
                handler(this, e);
            } else {
                e.Context.Response.Write(API_RETURN_FORBIDDEN);
                e.Context.Response.End();
            }
        }

        protected virtual void OnUpdateCredit(UCEventArgs e) {
            UCCallBack handler = ACTION_TRANS_EVENTS["updatecredit"] as UCCallBack;
            if (handler != null) {
                handler(this, e);
            } else {
                e.Context.Response.Write(API_RETURN_FORBIDDEN);
                e.Context.Response.End();
            }
        }

        protected virtual void OnGetCredit(UCEventArgs e) {
            UCCallBack handler = ACTION_TRANS_EVENTS["getcredit"] as UCCallBack;
            if (handler != null) {
                handler(this, e);
            } else {
                e.Context.Response.Write(API_RETURN_FORBIDDEN);
                e.Context.Response.End();
            }
        }

        protected virtual void OnGetCreditSettings(UCEventArgs e) {
            UCCallBack handler = ACTION_TRANS_EVENTS["getcreditsettings"] as UCCallBack;
            if (handler != null) {
                handler(this, e);
            } else {
                e.Context.Response.Write(API_RETURN_FORBIDDEN);
                e.Context.Response.End();
            }
        }

        protected virtual void OnUpdateCreditSettings(UCEventArgs e) {
            UCCallBack handler = ACTION_TRANS_EVENTS["updatecreditsettings"] as UCCallBack;
            if (handler != null) {
                handler(this, e);
            } else {
                e.Context.Response.Write(API_RETURN_FORBIDDEN);
                e.Context.Response.End();
            }
        }

        #endregion

        #region ActionTrans
        readonly static NV ACTION_TRANS_METHODS = new NV()
        { {"test", "UC_Test"},
          {"deleteuser", "UC_DeleteUser"},
          {"renameuser", "UC_RenameUser"},
          {"gettag", "UC_GetTag"},
          {"synlogin", "UC_SynLogin"},
          {"synlogout", "UC_SynLogout"},
          {"updatepw","UC_UpdatePassword"},
          {"updatebadwords", "UC_UpdateBadWords"},
          {"updatehosts", "UC_UpdateHosts"},
          {"updateapps", "UC_UpdateApps"},
          {"updateclient", "UC_UpdateClient"},
          {"updatecredit", "UC_UpdateCredit"},
          {"getcredit", "UC_GetCredit"},
          {"getcreditsettings", "UC_GetCreditSettings"},
          {"updatecreditsettings", "UC_UpdateCreditSettings"} };

        readonly static NV ACTION_TRANS = new NV()
        { {"test", "Test"},
          {"deleteuser", "DeleteUser"},
          {"renameuser", "RenameUser"},
          {"gettag", "GetTag"},
          {"synlogin", "SynLogin"},
          {"synlogout", "SynLogout"},
          {"updatepw","UpdatePassword"},
          {"updatebadwords", "UpdateBadWords"},
          {"updatehosts", "UpdateHosts"},
          {"updateapps", "UpdateApps"},
          {"updateclient", "UpdateClient"},
          {"updatecredit", "UpdateCredit"},
          {"getcredit", "GetCredit"},
          {"getcreditsettings", "GetCreditSettings"},
          {"updatecreditsettings", "UpdateCreditSettings"} };

        

        readonly Hashtable ACTION_TRANS_EVENTS = new Hashtable();
        protected UCApiHandler() {
            ACTION_TRANS_EVENTS = new Hashtable(15);
            ACTION_TRANS_EVENTS.Add("test", Test);
            ACTION_TRANS_EVENTS.Add("deleteuser", DeleteUser);
            ACTION_TRANS_EVENTS.Add("renameuser",RenameUser);
            ACTION_TRANS_EVENTS.Add("gettag",GetTag);
            ACTION_TRANS_EVENTS.Add("synlogin",SynLogin);
            ACTION_TRANS_EVENTS.Add("synlogout",SynLogout);
            ACTION_TRANS_EVENTS.Add("updatepw", UpdatePassword);
            ACTION_TRANS_EVENTS.Add("updatebadwords",UpdateBadWords);
            ACTION_TRANS_EVENTS.Add("updatehosts",UpdateHosts);
            ACTION_TRANS_EVENTS.Add("updateapps",UpdateApps);
            ACTION_TRANS_EVENTS.Add("updateclient",UpdateClient);
            ACTION_TRANS_EVENTS.Add("updatecredit",UpdateCredit);
            ACTION_TRANS_EVENTS.Add("getcredit",GetCredit);
            ACTION_TRANS_EVENTS.Add("getcreditsettings",GetCreditSettings);
            ACTION_TRANS_EVENTS.Add("updatecreditsettings",UpdateCreditSettings);
        }
        #endregion

        public void ProcessRequest(HttpContext context) {
//#if DEBUG
//            EventLog.WriteEntry("Application", "\n[UC_API_PRE]\n", EventLogEntryType.Information);
//#endif
            // HOOK UP MY EVENTS
            HookupUCEvents();

            // 处理请求
            string code = context.Request.QueryString["code"];
            if (string.IsNullOrEmpty(code)) {
                context.Response.Write(API_RETURN_FORBIDDEN);
                context.Response.End();
                return;
            }

            code = UCClient.AuthCode(code, "DECODE", UCConfig.UC_KEY);
            NV codeQS = HttpUtility.ParseQueryString(code);

            string timeStr = codeQS["time"];
            int timeInt = 0;
            if (string.IsNullOrEmpty(timeStr) ||
                !int.TryParse(timeStr, out timeInt)) {
                context.Response.Write("Invalid Request");
                context.Response.End();
                return;
            }

            if (UCClient.SecondsSince1970() - timeInt > 3600) {
                context.Response.Write("Authracation has expiried");
                context.Response.End();
                return;
            }

            string action = codeQS["action"];
            if (!ACTION_TRANS_EVENTS.ContainsKey(action)) {
                context.Response.Write(API_RETURN_FAILED);
                context.Response.End();
                return;
            }

#if DEBUG
            EventLog.WriteEntry("Application", string.Format("\n[UCAPI]\naction:{0}\ncode:{1}", action, code), EventLogEntryType.Information);
#endif

            // READ POST RAW DATA
            StreamReader sr = new StreamReader(context.Request.InputStream, Encoding.GetEncoding(UCConfig.UC_CHARSET));
            string post = sr.ReadToEnd();
            sr.Dispose();

            UCPostData postData = null;
            if (!string.IsNullOrEmpty(post)) {
                postData = UCXmlSerialization.Deserialize(post);
            }

            //if (postData != null) {

            // should call OnXxx
            MethodInfo handlerMethod = this.GetType().GetMethod("On" + ACTION_TRANS[action],
                BindingFlags.NonPublic | BindingFlags.Instance,
                null /*Binder*/,
                new Type[] { typeof(UCEventArgs) },
                null /*ParameterModifier[]*/);

            if (handlerMethod != null) {
                handlerMethod.Invoke(this, new object[] { new UCEventArgs(codeQS, postData, context) });
            }
            //}
        }

        private void HookupUCEvents() {
            // TODO: TEST IF SUPPORTED
            if (!true) {
                return;
            }

            // 寻找是否有定义
            foreach (string actionName in ACTION_TRANS_METHODS.AllKeys) {
                string methodName = ACTION_TRANS_METHODS[actionName];

                UCCallBack uccb = (UCCallBack)Delegate.CreateDelegate(typeof(UCCallBack), this,
                    methodName, true, false); 
                
                if (uccb != null) {
                    // 而且方法存在且符合委托协议
                    bool eventExists = false;
                    // 查看实例中的事件的情况
                    MethodInfo method = uccb.Method;
                    Delegate eventInstance = ACTION_TRANS_EVENTS[actionName] as UCCallBack;
                    if (eventInstance != null) {
                        foreach (Delegate eventDelegate in ((UCCallBack)ACTION_TRANS_EVENTS[actionName]).GetInvocationList()) {
                            // Ignore if this method is already added to the events list. 
                            if (eventDelegate.Method.Equals(method)) {
                                eventExists = true;
                                break;
                            }
                        }
                    }

                    if (!eventExists) {
                        ACTION_TRANS_EVENTS[actionName] = eventInstance = Delegate.Combine(uccb, eventInstance);
                    }
                }
            }
        }

        #region IHttpHandler Members

        public bool IsReusable {
            get { return false; }
        }

        #endregion
    }
}
